#include "sqliteEF.h"
#include <memory>

sqliteEF sqliteEF::m_sqliteEF;

sqliteEF::sqliteEF()
{

}

sqliteEF::~sqliteEF()
{
	sqlite3_close(db);
}

void sqliteEF::dealBakVal(sqlite3_stmt* pStmt, int index, sqliteEFVal &out_ef)
{
	out_ef.d_val = 0;
	out_ef.int_val = 0;
	out_ef.str_val = "";

	int iType = sqlite3_column_type(pStmt, index);
	if (iType == SQLITE_INTEGER)
	{
		out_ef.int_val = sqlite3_column_int(pStmt, index);
		out_ef.sType = sqliteEFType::type_int;
	}
	else if (iType == SQLITE_FLOAT)
	{
		out_ef.d_val = sqlite3_column_double(pStmt, index);
		out_ef.sType = sqliteEFType::type_double;
	}
	else if (iType == SQLITE_TEXT)
	{
		const unsigned char* val = sqlite3_column_text(pStmt, index);
		out_ef.str_val = string((char*)val);
		out_ef.sType = sqliteEFType::type_str;
	}
	else if (iType == SQLITE_NULL)
	{
		out_ef.null_val = "NULL";
		out_ef.sType = sqliteEFType::type_null;
	}
}


void sqliteEF::test()
{
	/*char sql[] = "SELECT * from admin_user";
	printf("sql %s\n", sql);
	auto tmp = findAlls(sql);*/
}

sqliteEFCols sqliteEF::find(string sql)
{
	sqliteEFCols tmp_map;

	sqliteEFVal tmpval;

	sqlite3_stmt* pStmt;
	int r = sqlite3_prepare_v2(
		db,
		sql.c_str(),
		sql.size(),
		&pStmt,
		NULL);

	if (r != SQLITE_OK)
	{
		perror("sqlite3_prepare_v2 error:");
		return tmp_map;
	}

	// static int first = 1;
	int i;
	r = sqlite3_step(pStmt);
	if (r == SQLITE_DONE)
	{
		printf("o la\n");
	}
	else if (r == SQLITE_ROW)
	{
		int cNum = sqlite3_column_count(pStmt);
		for (i = 0; i < cNum; i++)
		{
			dealBakVal(pStmt,i, tmpval);
			
			const char* p = sqlite3_column_name(pStmt, i);
			tmp_map.add(string(p), tmpval);
		}
	}

	sqlite3_finalize(pStmt);
	pStmt = NULL;

	return tmp_map;
}

void sqliteEF::init(string dbName)
{
	m_sqliteEF.m_dbName = dbName;

	int rc = sqlite3_open(m_sqliteEF.m_dbName.c_str(), &m_sqliteEF.db);

	if (rc)
	{
		fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(m_sqliteEF.db));
		exit(0);
	}
	else
	{
		fprintf(stderr, "Opened database successfully\n");
	}
}

sqliteEFRows sqliteEF::findAlls(string sql)
{
	sqliteEFRows tmp_map_list;
	sqliteEFCols tmp_map;

	sqliteEFVal tmpval;

	sqlite3_stmt* pStmt;
	int r = sqlite3_prepare_v2(
		db,
		sql.c_str(),
		sql.size(),
		&pStmt,
		NULL);

	if (r != SQLITE_OK)
	{
		perror("sqlite3_prepare_v2 error:");
		return tmp_map_list;
	}

	int i;
	while (1)
	{
		r = sqlite3_step(pStmt);
		if (r == SQLITE_DONE)
		{
			printf("rows end\n");
			break;
		}
		else if (r == SQLITE_ROW)
		{
			int cNum = sqlite3_column_count(pStmt);
			for (i = 0; i < cNum; i++)
			{
				dealBakVal(pStmt, i, tmpval);
				const char* p = sqlite3_column_name(pStmt, i);
				tmp_map.add(string(p), tmpval);
			}
			tmp_map_list.push_back(tmp_map);
		}
	}
	sqlite3_finalize(pStmt);
	pStmt = NULL;
	return tmp_map_list;
}


int sqliteEF::exec(string sql)
{
	std::lock_guard<std::mutex> lockGuard(lock_mutex);

	int bak = 0;
	sqlite3_stmt* stmt = NULL;

	int result = sqlite3_prepare_v2(db, sql.c_str(), sql.size(), &stmt, NULL);
	if (result == SQLITE_OK) {
		//执行该语句
		sqlite3_step(stmt);
		bak = 1;
	}
	else {
		bak = -1;
	}

	sqlite3_finalize(stmt);
	stmt = NULL;
	return bak;
}

string sqliteEFModel::toParCols(sqliteEFCols swhere, string checkWhere, string link)
{
	if (checkWhere.size() > 0)
	{
		checkWhere = "," + checkWhere + ",";
	}

	string str_w = "";
	sqliteEFCols::iterator col_it;
	bool isfirst = true;
	if ((int)this->sqlstr.find(" where ") > 0)
	{
		isfirst = false;
	}
	for (col_it = swhere.begin(); col_it != swhere.end(); col_it++)
	{
		if (checkWhere.size() > 0)
		{
			if ((int)checkWhere.find(col_it->first + ",") <= 0)
			{
				continue;
			}
		}
		if (isfirst)
		{
			isfirst = false;
			str_w += col_it->first + " = ";
		}
		else
		{
			str_w += link + col_it->first + " = ";
		}

		str_w += getValFromEFVal(col_it->second);
	}
	return str_w;
}

string sqliteEFModel::getValFromEFVal(sqliteEFVal val)
{
	string str_w = "";
	if (val.sType == sqliteEFType::type_str)
	{
		str_w = "'" + val.str_val + "'";
	}
	else if (val.sType == sqliteEFType::type_int)
	{
		str_w = to_string(val.int_val);
	}
	else if (val.sType == sqliteEFType::type_double)
	{
		str_w = to_string(val.d_val);
	}
	else if (val.sType == sqliteEFType::type_null)
	{
		str_w = val.null_val;
	}
	return str_w;
}

sqliteEFModel::sqliteEFModel(string sqlstr)
{
	this->sqlstr = sqlstr;
}

sqliteEFModel::sqliteEFModel(string sqlstr, string table)
{
	this->sqlstr = sqlstr;
	this->m_tableName = table;
}

sqliteEFModel::~sqliteEFModel()
{
	this->sqlstr = "";
}

sqliteEFModel sqliteEFModel::table(string tableName)
{
	this->m_tableName = tableName;
	return sqliteEFModel(*this);
}
sqliteEFModel sqliteEFModel::select(string select)
{
	this->sqlstr = "SELECT " + select + " from `" + this->m_tableName + "`";

	return sqliteEFModel(*this);
}
sqliteEFModel sqliteEFModel::where(string swhere)
{
	if ((int)this->sqlstr.find(" where ") < 0) 
	{
		this->sqlstr += " where ";
	}

	this->sqlstr += " " + swhere;

	return sqliteEFModel(*this);
}

sqliteEFModel sqliteEFModel::where(sqliteEFCols swhere, string checkWhere)
{
	return this->where(toParCols(swhere, checkWhere," and "));
}

sqliteEFModel sqliteEFModel::where_or(sqliteEFCols swhere, string checkWhere)
{
	return this->where(toParCols(swhere, checkWhere, " or "));
}

sqliteEFCols sqliteEFModel::find()
{
	this->sqlstr += " limit 1";
	return sqliteEF::GetClient()->find(this->sqlstr);
}
sqliteEFRows sqliteEFModel::findAlls()
{
	return sqliteEF::GetClient()->findAlls(this->sqlstr);
}

sqliteEFModel sqliteEFModel::update(string set)
{
	this->sqlstr = "update `" + this->m_tableName + "` set " + set;
	return sqliteEFModel(*this);
}

sqliteEFModel sqliteEFModel::update(sqliteEFCols swhere, string checkWhere)
{
	return this->update(toParCols(swhere, checkWhere, " , "));
}

sqliteEFModel sqliteEFModel::orderEsc(string sortstr)
{
	this->sqlstr += " order by " + sortstr;
	return sqliteEFModel(*this);
}

sqliteEFModel sqliteEFModel::orderDesc(string sortstr)
{
	this->sqlstr += " order by " + sortstr + " desc";
	return sqliteEFModel(*this);
}

sqliteEFModel sqliteEFModel::pages(int page,int pagesize)
{
	int beg = (page - 1) * pagesize;
	this->sqlstr += " limit " + to_string(beg) + "," + to_string(pagesize);
	return sqliteEFModel(*this);
}

sqliteEFModel sqliteEFModel::del()
{
	this->sqlstr = "DELETE FROM `" + m_tableName + "` ";
	return sqliteEFModel(*this);
}

sqliteEFModel sqliteEFModel::sql(string sql)
{
	this->sqlstr = sql;
	return sqliteEFModel(*this);
}

sqliteEFModel sqliteEFModel::insert(sqliteEFCols swhere, string checkWhere, bool isCheckWhere)
{
	if (checkWhere.size() > 0)
	{
		checkWhere = "," + checkWhere + ",";
	}

	string str_key = "";
	string str_val = "";
	sqliteEFCols::iterator col_it;
	bool isfirst = true;
	if ((int)this->sqlstr.find(" where ") > 0)
	{
		isfirst = false;
	}
	for (col_it = swhere.begin(); col_it != swhere.end(); col_it++)
	{
		if (checkWhere.size() > 0)
		{
			int findex = checkWhere.find(col_it->first + ",");
			if (isCheckWhere)
			{
				if (findex <= 0)
				{
					continue;
				}
			}
			else
			{
				if (findex > 0)
				{
					continue;
				}
			}
		}
		if (isfirst)
		{
			isfirst = false;
		}
		else
		{
			str_key += ",";
			str_val += ",";
		}

		str_key += "`" + col_it->first + "`";
		str_val += getValFromEFVal(col_it->second);

	}

	this->sqlstr = "INSERT INTO " + this->m_tableName + " (" + str_key + ") VALUES ("+ str_val + ")";
	return sqliteEFModel(*this);
}

sqliteEFCols sqliteEFModel::find(sqliteEFInPars pars)
{
	if (!pars.getCheckPar())
	{
		return sqliteEFCols();
	}
	string tmpsql = this->sqlstr;

	int find_index = 0;
	int qlien = pars.size();
	for (int i = 0; i < qlien; i++)
	{
		find_index = tmpsql.find('?', find_index);
		tmpsql.replace(find_index,1, pars[i] ,0, pars[i].size());
	}

	return sqliteEF::GetClient()->find(tmpsql);
}

sqliteEFRows sqliteEFModel::findAlls(sqliteEFInPars pars)
{
	if (!pars.getCheckPar())
	{
		return sqliteEFRows();
	}

	string tmpsql = this->sqlstr;

	int find_index = 0;
	int qlien = pars.size();
	for (int i = 0; i < qlien; i++)
	{
		find_index = tmpsql.find('?', find_index);
		if (find_index > 0)
		{
			tmpsql.replace(find_index,1, pars[i] ,0, pars[i].size());
		}
	}

	return sqliteEF::GetClient()->findAlls(tmpsql);
}

int sqliteEFModel::exec()
{
	return sqliteEF::GetClient()->exec(this->sqlstr);
}

int sqliteEFModel::exec(sqliteEFInPars pars)
{
	if (!pars.getCheckPar())
	{
		return -2;
	}

	string tmpsql = this->sqlstr;

	int find_index = 0;
	int qlien = pars.size();
	for (int i = 0; i < qlien; i++)
	{
		find_index = tmpsql.find('?', find_index);
		if (find_index > 0)
		{
			tmpsql.replace(find_index,1, pars[i] ,0, pars[i].size());
		}
		else
		{
			break;
		}
	}

	return sqliteEF::GetClient()->exec(tmpsql);
}


void sqliteEFModel::outStr(sqliteEFRows rows)
{
	sqliteEFRows::iterator it;
	std::cout << "\n----------begin rows-------------\n";
	for (it = rows.begin(); it != rows.end(); it++)
	{
		sqliteEFCols tmp = *it;
		outStr(tmp);
	}
	std::cout << "\n----------end rows-------------\n";
}

void sqliteEFModel::outStr(sqliteEFCols cols)
{
	sqliteEFCols::iterator col_it;
	for (col_it = cols.begin(); col_it != cols.end(); col_it++)
	{
		std::cout << col_it->first << ":";
		sqliteEFVal tmp_val = col_it->second;
		if (tmp_val.sType == sqliteEFType::type_int)
		{
			std::cout << tmp_val.int_val << ",";
		}
		else  if (tmp_val.sType == sqliteEFType::type_double)
		{
			std::cout << tmp_val.d_val << ",";
		}
		else  if (tmp_val.sType == sqliteEFType::type_str)
		{
			std::cout << tmp_val.str_val.c_str() << ",";
		}
	}
	std::cout << "\n";
}

sqliteEFInPars::sqliteEFInPars()
{
}

sqliteEFInPars::~sqliteEFInPars()
{
	m_squery.clear();
}

void sqliteEFInPars::add(int par)
{
	m_squery.push_back(to_string(par));
}

void sqliteEFInPars::add(string par)
{
	checkPar(par);
	m_squery.push_back("'" + par + "'");
}

void sqliteEFInPars::add(double par)
{
	m_squery.push_back(to_string(par));
}

int sqliteEFInPars::size()
{
	return m_squery.size();
}

string sqliteEFInPars::at(int index)
{
	if (index >= size())
	{
		return "";
	}
	return m_squery[index];
}

void sqliteEFInPars::clear()
{
	m_squery.clear();
	m_isCheck = true;
}

bool sqliteEFInPars::CheckPare(string a)
{
	transform(a.begin(), a.end(), a.begin(), ::tolower);
	static const string key[] = { "and ","exec ","insert ","select ","delete ","update ","count ","*","%","chr","mid" ,"master ","truncate ","char ","declare ",";","or ","-","+",",","drop ","\'"};
	for (int i = 0; i < 22; i++)
	{
		if (a.find(key[i]) != string::npos)
		{
			return false;
		}
	}
	return true;
}

bool sqliteEFInPars::checkPar(string a)
{
	m_isCheck = CheckPare(a);
	return m_isCheck;
}

sqliteEFCols::sqliteEFCols()
{
}

sqliteEFCols::~sqliteEFCols()
{
	m_clos.clear();
}

sqliteEFVal* sqliteEFCols::get(string key)
{
	return &m_clos[key];
}

void sqliteEFCols::add(string key, int val)
{
	if (!sqliteEFInPars::CheckPare(key))
	{
		return;
	}
	sqliteEFVal tval;
	tval.sType = sqliteEFType::type_int;
	tval.int_val = val;
	m_clos[key] = tval;
}

void sqliteEFCols::add(string key, double val)
{
	if (!sqliteEFInPars::CheckPare(key))
	{
		return;
	}
	sqliteEFVal tval;
	tval.sType = sqliteEFType::type_double;
	tval.d_val = val;
	m_clos[key] = tval;
}

void sqliteEFCols::add(string key, string val)
{
	if (sqliteEFInPars::CheckPare(val) && sqliteEFInPars::CheckPare(key))
	{
		sqliteEFVal tval;
		tval.sType = sqliteEFType::type_str;
		tval.str_val = val;
		m_clos[key] = tval;
	}
}

void sqliteEFCols::add(string key, sqliteEFVal val)
{
	if (sqliteEFInPars::CheckPare(key) && sqliteEFInPars::CheckPare(val.str_val))
	{
		m_clos[key] = val;
	}
}


sqliteEFCols::iterator& sqliteEFCols::begin()
{
	m_clos_it = m_clos.begin();
	return m_clos_it;
}

sqliteEFCols::iterator& sqliteEFCols::end()
{
	m_clos_it = m_clos.end();
	return m_clos_it;
}

void sqliteEFCols::clear()
{
	m_clos.clear();
}
int sqliteEFCols::size()
{
	return m_clos.size();
}